package core;

import java.util.HashMap;
import java.util.LinkedList;

import core.physics.CollisionDetectionAlgorithm;
import core.physics.CollisionManager;

/**
 * Responsible for advancing the state of the game forward.
 * 
 * Note that this engine is used both on the client and server side to allow for
 * the greatest synchronization.
 * 
 * @author Jason
 * 
 */
public class GameEngine {

	protected HashMap<Integer, Entity> idEntities = new HashMap<Integer, Entity>();
	protected CollisionManager collisionManager = new CollisionManager(null);

	/**
	 * Adds the specified entity to the engine.
	 * 
	 * @return True if successful, false if the entity already exists.
	 */
	public boolean addEntity(Entity entity) {
		if (idEntities.get(entity.id) == null) {
			idEntities.put(entity.id, entity);
			return true;
		}
		return false;
	}

	/**
	 * Gets the entity with the specified ID.
	 */
	public Entity getEntity(int id) {
		return idEntities.get(id);
	}

	/**
	 * Removes the specified entity.
	 */
	public void removeEntity(Entity entity) {
		idEntities.remove(entity.id);
	}

	/**
	 * Ticks all of the entities the given number of seconds.
	 */
	public void tick(double seconds) {
		for (Integer id : idEntities.keySet()) {
			Entity entity = idEntities.get(id);
			entity.tick(seconds);
		}
	}

	/**
	 * Synchronizes the inputted GameEngine with this one, adding entities that
	 * were changed to the entitiesChanged list. After this method is called,
	 * all entities from engine to engine will be .equals() equivalent.
	 * 
	 * @param engine
	 *            The engine to sync.
	 * @param entitiesChanged
	 *            A list of all the entities in the inputted engine that were
	 *            changed.
	 */
	public void synchronize(GameEngine engine,
			LinkedList<Entity> entitiesChanged) {
		for (Integer id : idEntities.keySet()) {
			Entity myEntity = idEntities.get(id);
			Entity otherEntity = engine.idEntities.get(myEntity.id);
			if (otherEntity == null) {
				Entity copy = myEntity.clone();
				entitiesChanged.add(copy);
				engine.addEntity(copy);
			} else if (!otherEntity.equals(myEntity)) {
				otherEntity.readAttributes(myEntity);
				entitiesChanged.add(otherEntity);
			}
		}
	}

	/**
	 * Sets the collision detection algorithm used by this engine.
	 * 
	 * @param alg
	 *            If this is null, no collisions will be detected.
	 */
	public void setCollisionDetectionAlgorithm(CollisionDetectionAlgorithm alg) {
		collisionManager.setAlgorithm(alg);
	}
}
